


using System;
using System.Collections;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Net.NetworkInformation;

using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;

namespace CommonNetduino
{

    # region Supporting Classes

    public class CSocketPacket
    {
        public System.Net.Sockets.Socket thisSocket;
        public byte[] dataBuffer = new byte[1];
    }

    public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs e);
    public delegate void MessageSentEventHandler(object sender, MessageEventArgs e);

    public delegate void MessageAcknowledgedEventHandler(object sender, MessageEventArgs e);
    public class MessageEventArgs : EventArgs
    {
        public MessageEventArgs(int port, string message)
        {
            this._port = port;
            this._message = message;
        }

        public MessageEventArgs(int port, byte[] b)
        {
            this._port = port;
            this._byteReceive = b;
        }

        public MessageEventArgs(int port, string message, byte[] b)
        {
            this._port = port;
            this._byteReceive = b;
        }

        private int _port;
        public int Port
        {
            get
            {
                return this._port;
            }
            set
            {
                this._port = value;
            }
        }

        private byte[] _byteReceive = null;
        public byte[] ByteReceive
        {
            get { return _byteReceive; }
            set { _byteReceive = value; }
        }

        private string _message = string.Empty;
        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                _message = value;
            }
        }
    }

    public delegate void HeartbeatEventHandler(object sender, HeartbeatEventArgs e);
    public class HeartbeatEventArgs : EventArgs
    {
        public HeartbeatEventArgs(string equipmentName)
        {
            this._equipmentName = equipmentName;
        }

        private string _equipmentName;
        public string EquipmentName
        {
            get
            {
                return this._equipmentName;
            }
            set
            {
                this._equipmentName = value;
            }
        }
    }

    public delegate void AcknowledgeEventHandler(object sender, AcknowledgeEventArgs e);
    public class AcknowledgeEventArgs : EventArgs
    {
        public AcknowledgeEventArgs(string equipmentName)
        {
            this._equipmentName = equipmentName;
        }

        private string _equipmentName;
        public string EquipmentName
        {
            get
            {
                return this._equipmentName;
            }
            set
            {
                this._equipmentName = value;
            }
        }
    }

    public delegate void ConnectedEventHandler(object sender, ConnectedEventArgs e);
    public class ConnectedEventArgs : EventArgs
    {
        public ConnectedEventArgs(string equipmentName, bool connected)
        {
            this._equipmentName = equipmentName;
            this._connected = connected;
        }

        private string _equipmentName;
        public string EquipmentName
        {
            get
            {
                return this._equipmentName;
            }
            set
            {
                this._equipmentName = value;
            }
        }

        private bool _connected;
        public bool Connected
        {
            get
            {
                return this._connected;
            }
            set
            {
                this._connected = value;
            }
        }
    }

    public delegate void Ack_NakEventHandler(object sender, Ack_NakEventArgs e);
    public class Ack_NakEventArgs : EventArgs
    {
        public Ack_NakEventArgs(bool ack_nak)
        {
            _Ack_Nak = ack_nak;
        }

        private bool _Ack_Nak = true;
        public bool AckNak
        {
            get { return _Ack_Nak; }
            set { _Ack_Nak = value; }
        }

    }

    #endregion

    #region "TCP Client"

    [Serializable]
    public class tcpCaller : IDisposable
    {
        #region Declarations

        private Thread TcpThread = null;
        Socket listener = null;
        private NetworkStream tcpStream = null;
        private bool socketOpen = true;
        private Int32 HeartBeatCounter = 10000;
        private bool blnHeartBeat = false;
        private Queue q = new Queue();
        private string[] receiveList = null;
        byte[] b2send = null;
        byte[] bReceive = null;

        #endregion

        #region Properties

        private bool _Connect = false;
        public bool isConnected
        {
            get { return _Connect; }
            set { _Connect = value; }
        }

        private byte _sequence = 0x00;
        public byte sequence
        {
            get { return _sequence; }
            set { _sequence = value; }
        }

        private int _port = 1000;
        public int Port
        {
            get
            {
                return _port;
            }
            set
            {
                _port = value;
            }
        }

        private string _hostname = "localhost";
        public string Hostname
        {
            get { return _hostname; }
            set { _hostname = value; }
        }

        private int iSize = 1024;
        public int Size
        {
            get { return iSize; }
            set { iSize = value; }
        }

        private bool _DEBUG = true;
        public bool DEBUG
        {
            get { return _DEBUG; }
            set { _DEBUG = value; }
        }

        private bool _Acknowledge = false;
        public bool Acknowledge
        {
            set { _Acknowledge = value; }
            get { return _Acknowledge; }
        }

        #endregion

        #region Events

        public event MessageReceivedEventHandler MessageReceived;
        public void FireMessageReceived(MessageEventArgs e)
        {
            if (MessageReceived != null && e != null)
            {
                MessageReceived(this, e);
            }
        }

        public event MessageSentEventHandler MessageSent;
        public void FireMessageSent(MessageEventArgs e)
        {
            if (MessageSent != null && e != null)
            {
                MessageSent(this, e);
            }
        }

        public event HeartbeatEventHandler HeartbeatReceived;
        public void FireHeartbeat(HeartbeatEventArgs e)
        {
            if (HeartbeatReceived != null)
            {
                HeartbeatReceived(this, e);
            }
        }

        public event AcknowledgeEventHandler AcknowledgeReceived;
        public void FireAcknowledge(AcknowledgeEventArgs e)
        {
            if (AcknowledgeReceived != null)
            {
                Acknowledge = true;  //signal from server
                AcknowledgeReceived(this, e);
            }
        }

        #endregion

        #region Constructor

        public tcpCaller()
        {

        }



        public tcpCaller(int port, string host, Int32 hbCounter, bool start, bool heartbeat)
        {
            this.Port = port;
            this.Hostname = host;
            blnHeartBeat = heartbeat;
            HeartBeatCounter = hbCounter;

            if (start) call();

        }


        public void Dispose()
        {
            if (TcpThread != null)
            {
                TcpThread.Join(500);
                TcpThread = null;
            }
        }

        #endregion

        #region Running

        public void call()
        {
            try
            {
                Debug.Print("initializing socket thread . . .");
                TcpThread = new Thread(new ThreadStart(Receive));
                TcpThread.Start();
            }
            catch (Exception ex)
            {
                Debug.Print("Initial thread error: " + ex.Message);
                TcpThread.Abort();
            }
        }



        private bool QueueData(char[] chars)
        {
            bool ret = false;
            try
            {
                foreach (char c in chars)
                {
                    if (c == (char)0x03) // This is the ASCII ETX char indicating the end of the message frame. (byte)q.Dequeue();
                    {
                        ret = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }
            return ret;
        }

        public void Receive()
        {

            try
            {
                int iCount = 0;
                Int32 hbCount = 0;
                char[] chars = null;
                Byte[] buffer = null;// new Byte[Size];
                string sReceive = string.Empty;

                NetworkInterface[] ip = NetworkInterface.GetAllNetworkInterfaces();
                for (int i = 0; i < ip.Length; i++)
                {
                    Debug.Print("My IP: " + ip[i].IPAddress);
                    Debug.Print("My Subnet: " + ip[i].SubnetMask);
                    Debug.Print("My gateway: " + ip[i].GatewayAddress);
                    ip[i].EnableDhcp();

                }

                Debug.Print("instanciate listener . . .");
                listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                Debug.Print("Parsing IP address > > >" + this.Hostname + ":" + this.Port.ToString());
                IPAddress ipAddress = IPAddress.Parse(this.Hostname);

                Debug.Print("instanciate End Point server . . .");
                IPEndPoint serverEndPoint = new IPEndPoint(ipAddress, this.Port);

                isConnected = true;

                #region "isConnected"
                while (isConnected)
                {
                    Debug.Print("Connecting to server");
                    listener.Connect(serverEndPoint);
                    Debug.Print("Connected . . .");
                    hbCount = 0;               
                    Debug.Print("Sent first heartbeat");

                    do
                    {
                        #region "try and catch"
                        try
                        {
                            buffer = new Byte[Size];
                            iCount = 0;
                            iCount = listener.Receive(buffer, Size, SocketFlags.None);
                            Debug.Print("Receive: " + iCount.ToString() + " char(s)");
                            #region "iCount if loop"
                            if (iCount > 0)
                            {
                                chars = Encoding.UTF8.GetChars(buffer);
                                Debug.Print("Char: " + new string(chars));

                                if (chars.Length > 0)
                                {
                                    if (QueueData(chars))
                                    {
                                        if (buffer.Length >= 10) sequence = buffer[9];
                                        sReceive = new String(chars);
                                        Debug.Print(DateTime.Now.ToString() + "\tRaw receive:--->" + sReceive + "<---");
                                        hbCount = 0;//we consider server exists as long as there is communication
                                    }
                                }
                            }
                            else
                            {
                                hbCount++;
                                if (hbCount == HeartBeatCounter)
                                {
                                    iCount = -1;
                                    Debug.Print("Start new connection when heartbeat timer expired . . .");
                                }
                            }
                            #endregion
                        }
                        catch (SocketException e)
                        {
                            Debug.Print(e.Message);
                            iCount = -1; //to get out of inner loop and start new connection
                            Debug.Print("Start new connection on Socket Exception . . .");
                        }
                        #endregion
                        if (!isConnected) iCount = -1;//disconnect from external controller
                    } while (iCount >= 0);
                    listener.Close();//close socket to start new one

                }///<code>first while loop</code>
                #endregion
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }
            finally
            {
                if (listener != null)
                {
                    listener.Close();
                    listener = null;
                }
            }


        }


        public void Send(byte[] dgram)
        {
            try
            {
                if (dgram.Length > 0)
                {
                    if (listener != null)
                    {
                        listener.Send(dgram);
                    }
                    else
                    {
                        Debug.Print("No server listen instantiation");
                    }
                }
                else
                {
                    Debug.Print("Telegram is empty . . .");
                }
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }
        }

        public void Stop()
        {
            try
            {
                isConnected = false;
                Thread.Sleep(500);
                if (listener != null)
                {
                    listener.Close();
                    Thread.Sleep(500);
                    listener = null;
                }

                if (TcpThread != null)
                {
                    TcpThread.Join(500);
                    TcpThread = null;
                }
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }
        }

        #endregion
    }

    #endregion


    //////////public class tcpServer : IDisposable
    //////////{
    //////////    #region Declarations

    //////////    private Thread TcpThread = null;
    //////////    Socket listener = null;
    //////////    private NetworkStream tcpStream = null;
    //////////    //private bool socketOpen = true;
    //////////    private bool blnHeartBeat = false;
    //////////    private Queue q = new Queue();
    //////////    //private string[] receiveList = null;
    //////////    byte[] b2send = null;
    //////////    //byte[] bReceive = null;

    //////////    byte[] _Heartbeat = new byte[12] { 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x03 };

    //////////    #endregion

    //////////    #region Properties

    //////////    private bool _Connect = false;
    //////////    public bool isConnected
    //////////    {
    //////////        get { return _Connect; }
    //////////        set { _Connect = value; }
    //////////    }

    //////////    private byte _sequence = 0x00;
    //////////    public byte sequence
    //////////    {
    //////////        get { return _sequence; }
    //////////        set { _sequence = value; }
    //////////    }

    //////////    private int _port = 1000;
    //////////    public int Port
    //////////    {
    //////////        get
    //////////        {
    //////////            return _port;
    //////////        }
    //////////        set
    //////////        {
    //////////            _port = value;
    //////////        }
    //////////    }

    //////////    private string _hostname = "localhost";
    //////////    public string Hostname
    //////////    {
    //////////        get { return _hostname; }
    //////////        set { _hostname = value; }
    //////////    }

    //////////    private int iSize = 1024;
    //////////    public int Size
    //////////    {
    //////////        get { return iSize; }
    //////////        set { iSize = value; }
    //////////    }

    //////////    private bool _DEBUG = true;
    //////////    public bool DEBUG
    //////////    {
    //////////        get { return _DEBUG; }
    //////////        set { _DEBUG = value; }
    //////////    }

    //////////    private bool _Acknowledge = false;
    //////////    public bool Acknowledge
    //////////    {
    //////////        set { _Acknowledge = value; }
    //////////        get { return _Acknowledge; }
    //////////    }

    //////////    #endregion

    //////////    #region Events

    //////////    public event MessageReceivedEventHandler MessageReceived;
    //////////    public void FireMessageReceived(MessageEventArgs e)
    //////////    {
    //////////        if (MessageReceived != null && e != null)
    //////////        {
    //////////            MessageReceived(this, e);
    //////////        }
    //////////    }

    //////////    public event MessageSentEventHandler MessageSent;
    //////////    public void FireMessageSent(MessageEventArgs e)
    //////////    {
    //////////        if (MessageSent != null && e != null)
    //////////        {
    //////////            MessageSent(this, e);
    //////////        }
    //////////    }

    //////////    public event HeartbeatEventHandler HeartbeatReceived;
    //////////    public void FireHeartbeat(HeartbeatEventArgs e)
    //////////    {
    //////////        if (HeartbeatReceived != null)
    //////////        {
    //////////            HeartbeatReceived(this, e);
    //////////        }
    //////////    }

    //////////    public event AcknowledgeEventHandler AcknowledgeReceived;
    //////////    public void FireAcknowledge(AcknowledgeEventArgs e)
    //////////    {
    //////////        if (AcknowledgeReceived != null)
    //////////        {
    //////////            Acknowledge = true;  //signal from server
    //////////            AcknowledgeReceived(this, e);
    //////////        }
    //////////    }

    //////////    #endregion

    //////////    public tcpServer()
    //////////    {

    //////////    }

    //////////    public tcpServer(int port, string host, bool start, bool heartbeat)
    //////////    {
    //////////        this.Port = port;
    //////////        this.Hostname = host;
    //////////        blnHeartBeat = heartbeat;
    //////////        if (start) call();

    //////////    }


    //////////    #region Running

    //////////    public void call()
    //////////    {
    //////////        try
    //////////        {
    //////////            Debug.Print("initializing socket thread . . .");
    //////////            TcpThread = new Thread(new ThreadStart(Receive));
    //////////            TcpThread.Start();
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print("Initial thread error: " + ex.Message);
    //////////            TcpThread.Abort();
    //////////        }
    //////////    }


    //////////    private bool QueueData(char[] chars)
    //////////    {
    //////////        bool ret = false;
    //////////        try
    //////////        {
    //////////            foreach (char c in chars)
    //////////            {

    //////////                if (c == (char)0x03) // This is the ASCII ETX char indicating the end of the message frame. (byte)q.Dequeue();
    //////////                {
    //////////                    ret = true;
    //////////                }
    //////////            }
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////        return ret;
    //////////    }

    //////////    public void Receive()
    //////////    {

    //////////        try
    //////////        {
    //////////            int iCount = 0;
    //////////            char[] chars = null;
    //////////            Byte[] buffer = null;
    //////////            string sReceive = string.Empty;

    //////////            Socket listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    //////////            IPAddress ipAddress = IPAddress.Parse(Hostname);

    //////////            listeningSocket.Bind(new IPEndPoint(ipAddress, Port));

    //////////            Debug.Print("Listening to client connection on " + Hostname + ":" + Port.ToString());
    //////////            listeningSocket.Listen(1);

    //////////            isConnected = true;

    //////////            #region "isConnected"
    //////////            while (isConnected)
    //////////            {
    //////////                listener = listeningSocket.Accept();
    //////////                Debug.Print("Connected to server");
    //////////                listener.ReceiveTimeout = -1; //wait infinitely to get response
    //////////                SendHeartbeat();
    //////////                Debug.Print("Sent first heartbeat");
    //////////                #region "try and catch"
    //////////                try
    //////////                {
    //////////                    buffer = new Byte[Size];
    //////////                    iCount = listener.Receive(buffer, Size, SocketFlags.None);
    //////////                    Debug.Print("Receive: " + iCount.ToString() + " char(s)");
    //////////                    if (iCount > 0)
    //////////                    {
    //////////                        chars = Encoding.UTF8.GetChars(buffer);
    //////////                        Debug.Print("Char: " + new string(chars));

    //////////                        if (chars.Length > 0)
    //////////                        {
    //////////                            if (QueueData(chars))
    //////////                            {
    //////////                                //chars = Encoding.UTF8.GetChars(bReceive);
    //////////                                if (buffer.Length >= 10) sequence = buffer[9];
    //////////                                sReceive = new String(chars);
    //////////                                Debug.Print(DateTime.Now.ToString() + "\tRaw receive:--->" + sReceive + "<---");
    //////////                                if (!isHeartBeat(chars))
    //////////                                {
    //////////                                    if (!isAcknowledge(chars))
    //////////                                    {
    //////////                                        FireMessageReceived(new MessageEventArgs(Port, sReceive));
    //////////                                        SendAck(chars);
    //////////                                    }
    //////////                                    else
    //////////                                    {
    //////////                                        sReceive = string.Empty;
    //////////                                        FireAcknowledge(new AcknowledgeEventArgs(this.Hostname));
    //////////                                    }
    //////////                                }
    //////////                                else
    //////////                                {
    //////////                                    SendHeartbeat();
    //////////                                    FireHeartbeat(new HeartbeatEventArgs(this.Hostname));
    //////////                                }
    //////////                            }
    //////////                        }
    //////////                        iCount = 0;
    //////////                    }
    //////////                }
    //////////                catch (SocketException e)
    //////////                {
    //////////                    Debug.Print(e.Message);
    //////////                }
    //////////                #endregion
    //////////            }///<code>ONLY we can establish connection</code>
    //////////            #endregion
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////        finally
    //////////        {
    //////////            if (tcpStream != null)
    //////////            {
    //////////                tcpStream.Close();
    //////////                tcpStream = null;
    //////////            }
    //////////            if (listener != null)
    //////////            {
    //////////                listener.Close();
    //////////                listener = null;
    //////////            }
    //////////        }


    //////////    }

    //////////    public bool isHeartBeat(char[] c)
    //////////    {
    //////////        bool bln = false;
    //////////        try
    //////////        {
    //////////            if (c.Length > 10)
    //////////            {
    //////////                if (c[10] == 0x30)
    //////////                {
    //////////                    bln = true;
    //////////                }
    //////////            }
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////        return bln;
    //////////    }

    //////////    public bool isAcknowledge(char[] c)
    //////////    {
    //////////        bool bln = false;
    //////////        try
    //////////        {
    //////////            if (c.Length > 10)
    //////////            {
    //////////                if (c[10] == 0x32)
    //////////                {
    //////////                    bln = true;
    //////////                }
    //////////            }
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////        return bln;
    //////////    }

    //////////    public void SendHeartbeat()
    //////////    {
    //////////        Send(_Heartbeat);
    //////////    }

    //////////    public void SendAck(char[] c)
    //////////    {

    //////////        try
    //////////        {
    //////////            string s = new string(c);
    //////////            byte[] b = Encoding.UTF8.GetBytes(s);
    //////////            //if (c.Length > 9)
    //////////            //    sequence = b[9];
    //////////            //else
    //////////            //    sequence = b[0];

    //////////            byte[] ACK = new byte[15] { 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, sequence, 0x32, 0x41, 0x43, 0x4B, 0x03 };

    //////////            Send(ACK);
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////    }

    //////////    public void SendNak(char[] c)
    //////////    {

    //////////        try
    //////////        {
    //////////            string s = new string(c);
    //////////            byte[] b = Encoding.UTF8.GetBytes(s);
    //////////            //sequence = b[9];

    //////////            byte[] NAK = new byte[15] { 0x02, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, sequence, 0x32, 0x4E, 0x41, 0x4B, 0x03 };

    //////////            Send(NAK);
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////    }

    //////////    public void SendXml(string s)
    //////////    {
    //////////        try
    //////////        {
    //////////            Queue q = new Queue();

    //////////            // ASCII STX character - start transmission.
    //////////            q.Enqueue(new byte[1] { 0x02 });

    //////////            // Add the length in ASCII format (8 characters)
    //////////            string length = s.Length.ToString("00000000");
    //////////            foreach (byte b in Encoding.UTF8.GetBytes(length))
    //////////                q.Enqueue(b);

    //////////            // The sequence number is the ASCII numeral as a byte.
    //////////            q.Enqueue(Encoding.UTF8.GetBytes(this.sequence.ToString("0")));

    //////////            // The type of message is XML = 1 (0x31 is "1" in ASCII)
    //////////            q.Enqueue(new byte[1] { 0x31 });

    //////////            // Add the full XML message.
    //////////            //b.AddRange(Conversion.StringToByteArray(s));
    //////////            q.Enqueue(Encoding.UTF8.GetBytes(s));

    //////////            // ASCII ETX character - end transmission.
    //////////            //b.AddRange(new byte[1] { 0x03 });
    //////////            q.Enqueue(new byte[1] { 0x03 });

    //////////            b2send = new byte[q.Count];
    //////////            for (int i = 0; i < q.Count; i++)
    //////////                b2send[i] = (byte)q.Dequeue();
    //////////            Send(b2send);


    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////    }

    //////////    public void Send(byte[] dgram)
    //////////    {
    //////////        try
    //////////        {
    //////////            if (dgram.Length > 0)
    //////////            {
    //////////                if (listener != null)
    //////////                {
    //////////                    listener.Send(dgram);
    //////////                }
    //////////                else
    //////////                {
    //////////                    Debug.Print("No server listen instantiation");
    //////////                }
    //////////            }
    //////////            else
    //////////            {
    //////////                Debug.Print("Telegram is empty . . .");
    //////////            }
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////    }

    //////////    public void Stop()
    //////////    {
    //////////        try
    //////////        {
    //////////            isConnected = false;
    //////////            Thread.Sleep(500);
    //////////            if (listener != null)
    //////////            {
    //////////                listener.Close();
    //////////                Thread.Sleep(500);
    //////////                listener = null;
    //////////            }

    //////////            if (TcpThread != null)
    //////////            {
    //////////                TcpThread.Join(500);
    //////////                TcpThread = null;
    //////////            }
    //////////        }
    //////////        catch (Exception ex)
    //////////        {
    //////////            Debug.Print(ex.Message);
    //////////        }
    //////////    }


    //////////    #endregion
    //////////}

    //#endregion
}
